//include standard headers
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <time.h>
#include <string>
//#include <glfw3.h>
//#include "GLFW\glfw3.h"
//#include "glm\glm.hpp"
#include "GLFW\glfw3.h"
#include "glm\glm.hpp"
using namespace glm;
#include "rapidxml.hpp"
using namespace rapidxml;


#include "Shape.h"
#include "Plane.h"
#include "Sphere.h"
#include "Triangle.h"
#include "Scene.h"
#include "Renderer.h"
#include "ImageBuffer.h"
#include "DiffuseShader.h"
#include "ReflectiveShader.h"
#include "SpecularShader.h"
#include "OBJLoader.h"
#include "XMLFileLoader.h"

#include "Stats.h"

#define IMG_WIDTH 512
#define IMG_HEIGHT 512

float raster[IMG_WIDTH * IMG_HEIGHT * 3];

void draw();
void copyImgToRaster(ImageBuffer *img);
void setPixel(int x, int y, vec4 _col);
static void error_callback(int error, const char* description){
	fprintf(stderr, description);
}
bool mousePressed = false;
bool redraw = true;

//for testing the vector, matrix, and stack classes
int main(void){
	GLFWwindow* window;
	glfwSetErrorCallback(error_callback);

	//initialize GLFW
	if (!glfwInit()){
		fprintf(stderr, "Failed to initialize GLFW\n");
		return -1;
	}
	//initialize the raster array
	for (int i = 0; i < IMG_WIDTH * IMG_HEIGHT * 3; i++){
		raster[i] = ((float)i) / (IMG_WIDTH * IMG_HEIGHT * 3);
	}

	//create the window
	window = glfwCreateWindow(IMG_WIDTH, IMG_HEIGHT, "Lab1", NULL, NULL);
		//the old way: glfwOpenWindow(512, 512, 0, 0, 0, 0, 32, 0, GLFW_WINDOW)
	//open a window and create its OpenGL context
	if (!window){
		fprintf(stderr, "Failed to open GLFW window.");
		glfwTerminate();
		return -1;
	}

	glfwMakeContextCurrent(window);

	//This might be the way to allow dynamically-sized arrays
	//int twenty = 29;
	//float *raster = new float[twenty];

	//ensure we can capture the escape key being pressed below
	//glfwEnable(GLFW_STICKY_KEYS);
	
	
	SceneManager* sceneMan = new SceneManager();
	//sceneMan->scene(theScene);
	XMLFileLoader sceneLoader = XMLFileLoader();
	sceneLoader.setScene(sceneMan);
	sceneLoader.loadFileToScene("with_box.xml");
	
	
	Renderer *render = sceneMan->getRender();
	ImageBuffer *img = sceneMan->getImg();
	copyImgToRaster(img);

	do{
		if (glfwGetKey(window, GLFW_KEY_KP_1) == GLFW_PRESS) {
			img->activeLayer(0);
			copyImgToRaster(img);
			redraw = true;
		}
		else if (glfwGetKey(window, GLFW_KEY_KP_2) == GLFW_PRESS) {
			if (img->layers() > 1){
				img->activeLayer(1);
				copyImgToRaster(img);
				redraw = true;
			}
		}
		else if (glfwGetKey(window, GLFW_KEY_KP_3) == GLFW_PRESS) {
			if (img->layers() > 2){
				img->activeLayer(2);
				copyImgToRaster(img);
				redraw = true;
			}
		}
		if (!mousePressed && glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS){
			mousePressed = true;
			double thex;
			double they;
			glfwGetCursorPos(window, &thex, &they);
			they = (double)IMG_HEIGHT - they;
			render->debugPixel((int)thex, (int)they);
		}
		else if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_RELEASE){
			mousePressed = false;
		}

		if (true){
			draw();

			//swap buffers
			glfwSwapBuffers(window);
		}
		
		glfwPollEvents();
	}//check if the ESC key was pressed or the window was closed
	while (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS && true /*glfwGetWindowParam(GLFW_OPENED)*/);

	glfwDestroyWindow(window);
	//close OpenGL window and terminate GLFW
	glfwTerminate();

	return 0;
}

void draw(){
	redraw = false;
	//red background
	glClearColor(0.6, 0, 0, 0);
	//clear the screen to the clear color
	glClear(GL_COLOR_BUFFER_BIT);

	//Draw the array of pixels (This is where you draw the values
	//you have stored in the array 'raster')
	glRasterPos2f(-1, -1);
	glDrawPixels(IMG_WIDTH, IMG_HEIGHT, GL_RGB, GL_FLOAT, raster);

	if (false){
		//save the old state so that you can set it back after you draw
		GLint oldmatrixmode;
		GLboolean depthWasEnabled = glIsEnabled(GL_DEPTH_TEST);
		glDisable(GL_DEPTH_TEST);
		glGetIntegerv(GL_MATRIX_MODE, &oldmatrixmode);
		glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity();
		glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity();

		

		//set the state back to what it was
		glPopMatrix();
		glMatrixMode(GL_MODELVIEW); glPopMatrix();
		glMatrixMode(oldmatrixmode);
		if (depthWasEnabled){
			glEnable(GL_DEPTH_TEST);
		}
	}
	glFlush();
}

void setPixel(int x, int y, vec4 _col){
	raster[((y * IMG_WIDTH) + x) * 3 + 0] = _col.r;
	raster[((y * IMG_WIDTH) + x) * 3 + 1] = _col.g;
	raster[((y * IMG_WIDTH) + x) * 3 + 2] = _col.b;
}

void copyImgToRaster(ImageBuffer *img){
	//put the image contents into the raster array
	for (int y = 0; y < IMG_HEIGHT; y++){
		//vector<vec4> theRow = img->rowAt(y);
		for (int x = 0; x < IMG_WIDTH; x++){
			setPixel(x, y, img->pixel(x, y));
		}
	}
}